package com.mihuo.compoent;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Redis 工具类 - 封装常用 Redis 操作
 * 使用前需确保已配置 RedisTemplate Bean
 *
 * 功能特性：
 * 1. 支持字符串、哈希、列表、集合、有序集合等数据类型操作
 * 2. 提供原子操作和批量操作方法
 * 3. 包含完整的异常处理和日志记录
 * 4. 线程安全，基于Spring容器管理
 *
 * @author mihuo
 * @version 1.1
 */
@Slf4j
@Component
public class RedisUtil {

    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 构造方法注入RedisTemplate
     * @param redisTemplate Redis模板实例
     */
    public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
        log.info("RedisUtil初始化完成");
    }

    // ====================== 基础键值操作 ======================

    /**
     * 设置键值对，可设置过期时间
     * @param key 键，不能为null或空
     * @param value 值，不能为null
     * @param expire 过期时间(秒)，0表示永久
     * @return true成功 false失败
     */
    public boolean set(String key, Object value, long expire) {
        if (!validateKey(key) || value == null) {
            log.warn("设置缓存失败：键或值无效，key: {}, value: {}", key, value);
            return false;
        }

        try {
            if (expire > 0) {
                redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS);
            } else {
                redisTemplate.opsForValue().set(key, value);
            }
            return true;
        } catch (Exception e) {
            log.error("设置缓存异常，key: {}, error: {}", key, e.getMessage());
            return false;
        }
    }

    /**
     * 设置永久键值对
     * @param key 键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        return set(key, value, 0);
    }

    /**
     * 获取值
     * @param key 键
     * @return 值，键不存在或异常时返回null
     */
    public Object get(String key) {
        if (!validateKey(key)) {
            return null;
        }

        try {
            Object value = redisTemplate.opsForValue().get(key);
            return value;
        } catch (Exception e) {
            log.error("获取缓存异常，key: {}, error: {}", key, e.getMessage());
            return null;
        }
    }

    /**
     * 获取字符串值（安全转换）
     * @param key 键
     * @return 字符串值，转换失败返回null
     */
    public String getStr(String key) {
        Object value = get(key);
        if (value instanceof String) {
            return (String) value;
        }
        return value != null ? value.toString() : null;
    }

    /**
     * 设置过期时间
     * @param key 键
     * @param time 过期时间(秒)
     * @return true成功 false失败
     */
    public boolean expire(String key, long time) {
        if (!validateKey(key) || time <= 0) {
            return false;
        }

        try {
            Boolean result = redisTemplate.expire(key, time, TimeUnit.SECONDS);
            return result != null && result;
        } catch (Exception e) {
            log.error("设置过期时间异常，key: {}, error: {}", key, e.getMessage());
            return false;
        }
    }

    /**
     * 获取剩余过期时间
     * @param key 键
     * @return 剩余时间(秒)，-2表示键不存在，-1表示永久
     */
    public long getExpire(String key) {
        if (!validateKey(key)) {
            return -2;
        }

        try {
            Long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS);
            return expire != null ? expire : -2;
        } catch (Exception e) {
            log.error("获取过期时间异常，key: {}, error: {}", key, e.getMessage());
            return -2;
        }
    }

    /**
     * 判断键是否存在
     * @param key 键
     * @return true存在 false不存在
     */
    public boolean hasKey(String key) {
        if (!validateKey(key)) {
            return false;
        }

        try {
            Boolean exists = redisTemplate.hasKey(key);
            return exists != null && exists;
        } catch (Exception e) {
            log.error("判断键是否存在异常，key: {}, error: {}", key, e.getMessage());
            return false;
        }
    }

    /**
     * 删除键
     * @param keys 键数组
     * @return 实际删除的键数量
     */
    public long del(String... keys) {
        if (keys == null || keys.length == 0) {
            return 0;
        }

        try {
            Long deleteCount;
            if (keys.length == 1) {
                Boolean result = redisTemplate.delete(keys[0]);
                deleteCount = result != null && result ? 1L : 0L;
            } else {
                deleteCount = redisTemplate.delete(Arrays.asList(keys));
            }
            return deleteCount != null ? deleteCount : 0;
        } catch (Exception e) {
            log.error("删除缓存异常，keys: {}, error: {}", Arrays.toString(keys), e.getMessage());
            return 0;
        }
    }

    // ====================== 哈希操作 ======================

    /**
     * 设置哈希字段值
     * @param key 键
     * @param field 字段
     * @param value 值
     * @return true成功 false失败
     */
    public boolean hset(String key, String field, Object value) {
        if (!validateKey(key) || !validateField(field) || value == null) {
            return false;
        }

        try {
            redisTemplate.opsForHash().put(key, field, value);
            return true;
        } catch (Exception e) {
            log.error("设置哈希字段异常，key: {}, field: {}, error: {}", key, field, e.getMessage());
            return false;
        }
    }

    /**
     * 获取哈希字段值
     * @param key 键
     * @param field 字段
     * @return 字段值，不存在返回null
     */
    public Object hget(String key, String field) {
        if (!validateKey(key) || !validateField(field)) {
            return null;
        }

        try {
            return redisTemplate.opsForHash().get(key, field);
        } catch (Exception e) {
            log.error("获取哈希字段异常，key: {}, field: {}, error: {}", key, field, e.getMessage());
            return null;
        }
    }

    /**
     * 获取整个哈希表
     * @param key 键
     * @return 哈希表，键不存在返回空Map
     */
    public Map<Object, Object> hgetAll(String key) {
        if (!validateKey(key)) {
            return Collections.emptyMap();
        }

        try {
            Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);
            return entries != null ? entries : Collections.emptyMap();
        } catch (Exception e) {
            log.error("获取整个哈希表异常，key: {}, error: {}", key, e.getMessage());
            return Collections.emptyMap();
        }
    }

    /**
     * 删除哈希字段
     * @param key 键
     * @param fields 字段数组
     * @return 实际删除的字段数量
     */
    public long hdel(String key, Object... fields) {
        if (!validateKey(key) || fields == null || fields.length == 0) {
            return 0;
        }

        try {
            Long deleteCount = redisTemplate.opsForHash().delete(key, fields);
            return deleteCount != null ? deleteCount : 0;
        } catch (Exception e) {
            log.error("删除哈希字段异常，key: {}, fields: {}, error: {}", key, Arrays.toString(fields), e.getMessage());
            return 0;
        }
    }

    /**
     * 判断哈希字段是否存在
     * @param key 键
     * @param field 字段
     * @return true存在 false不存在
     */
    public boolean hHasKey(String key, String field) {
        if (!validateKey(key) || !validateField(field)) {
            return false;
        }

        try {
            return redisTemplate.opsForHash().hasKey(key, field);
        } catch (Exception e) {
            log.error("判断哈希字段是否存在异常，key: {}, field: {}, error: {}", key, field, e.getMessage());
            return false;
        }
    }

    /**
     * 哈希字段递增
     * @param key 键
     * @param field 字段
     * @param delta 增量（必须为正数）
     * @return 递增后的值
     */
    public double hincr(String key, String field, double delta) {
        if (!validateKey(key) || !validateField(field) || delta < 0) {
            throw new IllegalArgumentException("参数无效：键、字段不能为空，增量必须为正数");
        }

        try {
            return redisTemplate.opsForHash().increment(key, field, delta);
        } catch (Exception e) {
            log.error("哈希字段递增异常，key: {}, field: {}, delta: {}, error: {}", key, field, delta, e.getMessage());
            throw new RuntimeException("Redis操作失败", e);
        }
    }

    /**
     * 哈希字段递减
     * @param key 键
     * @param field 字段
     * @param delta 减量（必须为正数）
     * @return 递减后的值
     */
    public double hdecr(String key, String field, double delta) {
        return hincr(key, field, -delta);
    }

    // ====================== 列表操作 ======================

    /**
     * 左推入列表
     * @param key 键
     * @param value 值
     * @return 推入后列表的长度
     */
    public long lpush(String key, Object value) {
        if (!validateKey(key) || value == null) {
            return 0;
        }

        try {
            Long size = redisTemplate.opsForList().leftPush(key, value);
            return size != null ? size : 0;
        } catch (Exception e) {
            log.error("左推入列表异常，key: {}, error: {}", key, e.getMessage());
            return 0;
        }
    }

    /**
     * 右推入列表
     * @param key 键
     * @param value 值
     * @return 推入后列表的长度
     */
    public long rpush(String key, Object value) {
        if (!validateKey(key) || value == null) {
            return 0;
        }

        try {
            Long size = redisTemplate.opsForList().rightPush(key, value);
            return size != null ? size : 0;
        } catch (Exception e) {
            log.error("右推入列表异常，key: {}, error: {}", key, e.getMessage());
            return 0;
        }
    }

    /**
     * 获取列表范围
     * @param key 键
     * @param start 开始索引（0-based）
     * @param end 结束索引（-1表示到最后）
     * @return 列表范围，键不存在返回空列表
     */
    public List<Object> lrange(String key, long start, long end) {
        if (!validateKey(key)) {
            return Collections.emptyList();
        }

        try {
            List<Object> range = redisTemplate.opsForList().range(key, start, end);
            return range != null ? range : Collections.emptyList();
        } catch (Exception e) {
            log.error("获取列表范围异常，key: {}, start: {}, end: {}, error: {}", key, start, end, e.getMessage());
            return Collections.emptyList();
        }
    }

    /**
     * 获取列表长度
     * @param key 键
     * @return 列表长度，键不存在返回0
     */
    public long llen(String key) {
        if (!validateKey(key)) {
            return 0;
        }

        try {
            Long size = redisTemplate.opsForList().size(key);
            return size != null ? size : 0;
        } catch (Exception e) {
            log.error("获取列表长度异常，key: {}, error: {}", key, e.getMessage());
            return 0;
        }
    }

    // ====================== 集合操作 ======================

    /**
     * 添加集合元素
     * @param key 键
     * @param values 值数组
     * @return 成功添加的新元素数量
     */
    public long sadd(String key, Object... values) {
        if (!validateKey(key) || values == null || values.length == 0) {
            return 0;
        }

        try {
            Long addCount = redisTemplate.opsForSet().add(key, values);
            return addCount != null ? addCount : 0;
        } catch (Exception e) {
            log.error("添加集合元素异常，key: {}, values: {}, error: {}", key, Arrays.toString(values), e.getMessage());
            return 0;
        }
    }

    /**
     * 获取集合所有成员
     * @param key 键
     * @return 集合成员，键不存在返回空集合
     */
    public Set<Object> smembers(String key) {
        if (!validateKey(key)) {
            return Collections.emptySet();
        }

        try {
            Set<Object> members = redisTemplate.opsForSet().members(key);
            return members != null ? members : Collections.emptySet();
        } catch (Exception e) {
            log.error("获取集合所有成员异常，key: {}, error: {}", key, e.getMessage());
            return Collections.emptySet();
        }
    }

    /**
     * 判断是否为集合成员
     * @param key 键
     * @param value 值
     * @return true是成员 false不是成员
     */
    public boolean sismember(String key, Object value) {
        if (!validateKey(key) || value == null) {
            return false;
        }

        try {
            Boolean isMember = redisTemplate.opsForSet().isMember(key, value);
            return isMember != null && isMember;
        } catch (Exception e) {
            log.error("判断集合成员异常，key: {}, value: {}, error: {}", key, value, e.getMessage());
            return false;
        }
    }

    /**
     * 获取集合大小
     * @param key 键
     * @return 集合大小，键不存在返回0
     */
    public long scard(String key) {
        if (!validateKey(key)) {
            return 0;
        }

        try {
            Long size = redisTemplate.opsForSet().size(key);
            return size != null ? size : 0;
        } catch (Exception e) {
            log.error("获取集合大小异常，key: {}, error: {}", key, e.getMessage());
            return 0;
        }
    }

    // ====================== 有序集合操作 ======================

    /**
     * 添加有序集合元素
     * @param key 键
     * @param value 值
     * @param score 分数
     * @return true成功 false失败
     */
    public boolean zadd(String key, Object value, double score) {
        if (!validateKey(key) || value == null) {
            return false;
        }

        try {
            Boolean success = redisTemplate.opsForZSet().add(key, value, score);
            return success != null && success;
        } catch (Exception e) {
            log.error("添加有序集合元素异常，key: {}, value: {}, score: {}, error: {}", key, value, score, e.getMessage());
            return false;
        }
    }

    /**
     * 获取有序集合范围（按分数升序）
     * @param key 键
     * @param start 开始索引
     * @param end 结束索引
     * @return 有序集合范围，键不存在返回空集合
     */
    public Set<Object> zrange(String key, long start, long end) {
        if (!validateKey(key)) {
            return Collections.emptySet();
        }

        try {
            Set<Object> range = redisTemplate.opsForZSet().range(key, start, end);
            return range != null ? range : Collections.emptySet();
        } catch (Exception e) {
            log.error("获取有序集合范围异常，key: {}, start: {}, end: {}, error: {}", key, start, end, e.getMessage());
            return Collections.emptySet();
        }
    }

    // ====================== 原子操作 ======================

    /**
     * 原子递增
     * @param key 键
     * @param delta 增量（必须为正数）
     * @return 递增后的值
     */
    public long incr(String key, long delta) {
        if (!validateKey(key) || delta < 0) {
            throw new IllegalArgumentException("参数无效：键不能为空，增量必须为正数");
        }

        try {
            return redisTemplate.opsForValue().increment(key, delta);
        } catch (Exception e) {
            log.error("原子递增异常，key: {}, delta: {}, error: {}", key, delta, e.getMessage());
            throw new RuntimeException("Redis操作失败", e);
        }
    }

    /**
     * 原子递减
     * @param key 键
     * @param delta 减量（必须为正数）
     * @return 递减后的值
     */
    public long decr(String key, long delta) {
        return incr(key, -delta);
    }

    // ====================== 批量操作 ======================

    /**
     * 批量设置键值
     * @param map 键值对映射
     * @return true成功 false失败
     */
    public boolean multiSet(Map<String, Object> map) {
        if (CollectionUtils.isEmpty(map)) {
            return false;
        }

        try {
            redisTemplate.opsForValue().multiSet(map);
            return true;
        } catch (Exception e) {
            log.error("批量设置缓存异常，error: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 批量获取值
     * @param keys 键列表
     * @return 值列表，与键顺序对应，不存在的键对应null
     */
    public List<Object> multiGet(List<String> keys) {
        if (CollectionUtils.isEmpty(keys)) {
            return Collections.emptyList();
        }

        try {
            List<Object> values = redisTemplate.opsForValue().multiGet(keys);
            return values != null ? values : Collections.emptyList();
        } catch (Exception e) {
            log.error("批量获取缓存异常，keys: {}, error: {}", keys, e.getMessage());
            return Collections.emptyList();
        }
    }

    // ====================== 私有工具方法 ======================

    /**
     * 验证键有效性
     * @param key 键
     * @return true有效 false无效
     */
    private boolean validateKey(String key) {
        if (key == null || key.trim().isEmpty()) {
            return false;
        }
        return true;
    }

    /**
     * 验证字段有效性
     * @param field 字段
     * @return true有效 false无效
     */
    private boolean validateField(String field) {
        if (field == null || field.trim().isEmpty()) {
            log.warn("Redis字段无效: {}", field);
            return false;
        }
        return true;
    }
}